﻿//========================================================= 
/**@file JniCmdDriver.h
 * @brief 使用Jni方式回调的设备操作命令
 * 
 * @date 2016-10-03   10:51:18
 * @author Zhyioo 
 * @version 1.0
 */ 
//--------------------------------------------------------- 
#ifndef _LIBZHOUYB_JNICMDDRIVER_H_
#define _LIBZHOUYB_JNICMDDRIVER_H_
//--------------------------------------------------------- 
#include "../CommonCmdDriver.h"
#include "../CommandRunner.h"

#include <extension/ability/JniInvoker.h>
using zhou_yb::extension::ability::JniConverter;
using zhou_yb::extension::ability::JniInvoker;

#include <extension/ability/JavaIInteractiveTransInvoker.h>
using zhou_yb::extension::ability::JavaIInteractiveTransInvoker;

#include <extension/ability/JavaITransceiveTransInvoker.h>
using zhou_yb::extension::ability::JavaITransceiveTransInvoker;

#include <extension/ability/JniInvokerDevice.h>
using zhou_yb::extension::ability::JniInvokerDevice;
//--------------------------------------------------------- 
namespace zhou_yb {
namespace application {
namespace driver {
//--------------------------------------------------------- 
/// Jni设备
class JniDevice : public JniInvoker, public JniInvokerDevice
{
public:
    JniDevice() : JniInvoker(), JniInvokerDevice()
    {
        ArraySize = DEV_BUFFER_SIZE;
    }
    /// 初始化Jni调用
    virtual bool JniEnvCreate(JNIEnv* env, jobject obj)
    {
        LOG_FUNC_NAME();
        LOGGER(_log << "JniEnv*:<" << _hex_num(env) << ">,jobject:<" << _hex_num(obj) << ">\n");
        bool bCreate = JniInvoker::Create(env, obj);
        LOGGER(_log << "JniInvoker Create:<" << bCreate << ">\n");
        if(bCreate)
        {
            bCreate = JniInvokerDevice::Open(*this, ArraySize);
            LOGGER(_log << "JniDevice Open:<" << bCreate << ">\n");
            if(!bCreate)
            {
                JniInvoker::Dispose();
            }
        }
        return bCreate;
    }
    /// 缓冲区大小
    size_t ArraySize;
    /// 释放资源
    virtual void JniEnvDispose()
    {
        LOG_FUNC_NAME();
        LOGGER(_log.WriteLine("JniInvoker.Dispose"));
        LOGGER(_log.WriteLine("JniDevice.Dispose"));

        JniInvoker::Dispose();
        JniInvokerDevice::Close();
    }
};
//---------------------------------------------------------
/// Jni封装基于Java层OnRead/OnWrite的设备
template<class T>
class JniHandlerDevice : public T
{
protected:
    ByteBuilder _cacheBuff;
public:
    jboolean OnWrite(JniInvoker& jni, jbyteArray sCmd, jint sLen, jint nTimeoutMs)
    {
        JniConverter cvt(jni);
        ByteBuilder buff(32);
        cvt.get_jbyteArray(sCmd, sLen, buff);
        size_t len = T::template OnWrite<typename T::WriterType>(buff, nTimeoutMs);
        bool bOK = (len > 0);
        return bOK ? JNI_TRUE : JNI_FALSE;
    }
    jboolean OnRead(JniInvoker& jni, jbyteArray rCmd, jintArray rLen, jint nTimeoutMs)
    {
        if(_cacheBuff.IsEmpty())
        {
            size_t len = T::template OnRead<typename T::ReaderType>(_cacheBuff, nTimeoutMs);
            if(len < 1)
                return JNI_FALSE;
        }
        size_t size = jni->GetArrayLength(rCmd);
        size_t copylen = _min(size, _cacheBuff.GetLength());
        JniConverter cvt(jni);
        cvt.set_jbyteArray(_cacheBuff.SubArray(0, copylen), rCmd);
        jint len = static_cast<jint>(copylen);
        cvt.set_jintArray(&len, 1, rLen);

        // 接收的缓冲区比实际收到的有效数据小,缓存后下次拷贝
        if(size < _cacheBuff.GetLength())
        {
            _cacheBuff.RemoveFront(copylen);
        }
        else
        {
            _cacheBuff.Clear();
        }
        return JNI_TRUE;
    }
};
//--------------------------------------------------------- 
/// Jni导出驱动辅助函数
class JniDriverHelper
{
protected:
    JniDriverHelper() {}
public:
    /// 发送指令
    template<class TJniDriver>
    static jboolean Jni_TransmitCommand(TJniDriver& drv, JNIEnv *env, jobject obj, jstring sCmd, jstring sArg, ByteBuilder& sRecv)
    {
        JniConverter cvt(env);
        string cmd = cvt.get_string(sCmd);
        string arg = cvt.get_string(sArg);
        ByteBuilder sJniEnv(32);
        ByteBuilder tmp(8);
        typename TJniDriver::ArgParserType argParser;
        StringArguments jniArg;
        jniArg.Put("JNIEnv", ArgConvert::ToString<pointer>(reinterpret_cast<pointer>(env)));
        jniArg.Put("jobject", ArgConvert::ToString<pointer>(reinterpret_cast<pointer>(obj)));
        argParser.ToString(jniArg, sJniEnv);
        drv.TransmitCommand("JniEnvCreate", sJniEnv, tmp);
        tmp.Clear();
        bool bCommand = drv.TransmitCommand(cmd.c_str(), ByteArray(arg.c_str(), arg.length()), sRecv);
        drv.TransmitCommand("JniEnvDispose", sJniEnv, tmp);
        return bCommand ? JNI_TRUE : JNI_FALSE;
    }
    template<class TArgParser>
    static jboolean Jni_TransmitCommand(CommandRunner& runner, const char* devId,
        JNIEnv *env, jobject jobj, jstring sModule, jstring sCmd, jstring sArg, ByteBuilder& sRecv)
    {
        JniConverter cvt(env);
        string module = cvt.get_string(sModule);
        string cmd = cvt.get_string(sCmd);
        string arg = cvt.get_string(sArg);
        CommandRunnerActuator actuator(runner);
        TArgParser parser;

        bool isDevExist = (devId != NULL);
        StringArguments jniArg;
        if(isDevExist)
        {
            jniArg.Put("JNIEnv", ArgConvert::ToString<pointer>(reinterpret_cast<pointer>(env)));
            jniArg.Put("jobject", ArgConvert::ToString<pointer>(reinterpret_cast<pointer>(jobj)));

            actuator.Set(devId).Arg(jniArg).Run("Open").Reset();
        }

        bool bOK = false;
        actuator.Set(module).Arg(parser, arg.c_str()).Run(cmd.c_str(), false, &bOK);
        DeviceError::ErrorCode errCode = DeviceError::OperatorErr;
        if(!bOK)
        {
            actuator.OnCall("LastError");
            if(DeviceError::IsSuccess(actuator.Result()["CODE"].To<int>()))
            {
                string sMsg = cmd;
                sMsg += "执行失败";
                StringArguments::Set(actuator.Result(), "CODE", ArgConvert::ToString(errCode));
                StringArguments::Set(actuator.Result(), "MSG", sMsg);
            }
        }
        else
        {
            errCode = DeviceError::Success;
        }
        string sOK = "";
        if(!actuator.Result().Get("CODE", sOK))
        {
            actuator.Result().Put("CODE", ArgConvert::ToString(static_cast<int>(errCode)));
            if(!bOK)
            {
                sOK = cmd;
                sOK += "失败";
                actuator.Result().Put("MSG", sOK);
            }
        }
        actuator.Result(parser, sRecv).Reset();
        if(isDevExist)
        {
            actuator.Set(devId).Arg(jniArg).Run("Close").Reset();
        }
        return bOK ? JNI_TRUE : JNI_FALSE;
    }
};
//--------------------------------------------------------- 
/// 直接回调IInteractiveTrans接口进行通信的命令驱动
class JniInvokeCmdDriver : public CommonCmdDriver
{
protected:
    Ref<IBaseDevice> _activeDev;
    Ref<IInteractiveTrans> _activeTrans;

    size_t _jniArraySize;
    JniInvoker _jni;
    JavaIInteractiveTransInvoker _jnidev;

    bool _IsOpen()
    {
        return _jni.IsValid() && _jnidev.IsValid();
    }
public:
    JniInvokeCmdDriver() : CommonCmdDriver()
    {
        _jniArraySize = DEV_BUFFER_SIZE;
        _activeTrans = _jnidev;

        _errGetter.Add(_jnidev);
        _logSetter.select(_jnidev);

        _RegisteCMD(JniInvokeCmdDriver, SetArraySize);
        _Registe("JniEnvCreate", _MakeCMD(JniInvokeCmdDriver, Open));
        _Registe("JniEnvDispose", _MakeCMD(JniInvokeCmdDriver, Close));

        _RegisteExceptCMD(JniInvokeCmdDriver);
        _RegisteIBaseDeviceCMD(JniInvokeCmdDriver);
        _RegisteIInteractiveTransCMD(JniInvokeCmdDriver);

        _RegisteInterfaceCMD(JniInvokeCmdDriver, IInteractiveTrans);
    }
    /* Interface */
    LC_CMD_INTERFACE_GETTER(IInteractiveTrans, _activeTrans);
    /**
     * @brief JNI初始化
     * @date 2016-06-14 20:38
     * 
     * @param [in] JNIEnv : pointer JniEnv虚拟器地址
     * @param [in] jobject : pointer Java上层对象地址
     * @param [in] ArraySize : size_t [default:Null] 缓冲区大小
     */
    LC_CMD_METHOD(Open)
    {
        string sEnv = arg["JNIEnv"].To<string>("");
        string sObj = arg["jobject"].To<string>("");

        JNIEnv* env = reinterpret_cast<JNIEnv*>(ArgConvert::FromString<pointer>(sEnv));
        jobject obj = reinterpret_cast<jobject>(ArgConvert::FromString<pointer>(sObj));

        LOGGER(_log << "sEnv:" << sEnv << " env:" << _hex_num(env) << endl);
        LOGGER(_log << "sObj:" << sObj << " obj:" << _hex_num(obj) << endl);

        SetArraySize(arg, rlt);

        if(_jni.Create(env, obj))
        {
            if(_jnidev.Create(_jni, _jniArraySize))
            {
                return true;
            }
            _logErr(DeviceError::DevInitErr, "JniDev Create失败");
        }
        else
        {
            _logErr(DeviceError::DevInitErr, "Jni Create失败");
        }
        return false;
    }
    LC_CMD_METHOD(IsOpen)
    {
        ASSERT_FuncErr(_IsOpen(), DeviceError::DevAlreadyCloseErr);
        return true;
    }
    LC_CMD_METHOD(Close)
    {
        _jnidev.Dispose();
        _jni.Dispose();
        return true;
    }
    /**
     * @brief 设置JNI调用时的缓冲区大小
     * @date 2016-06-14 20:38
     * 
     * @param [in] ArraySize : size_t 缓冲区大小
     */
    LC_CMD_METHOD(SetArraySize)
    {
        string sArraySize;
        if(!arg.Get("ArraySize", sArraySize))
            return false;
        _jniArraySize = ArgConvert::FromString<uint>(sArraySize);
        if(_IsOpen())
        {
            return _jnidev.Create(_jni, _jniArraySize);
        }
        return true;
    }
    LC_CMD_EXCEPT()
    {
        EXCEPT_CMD(SetArraySize);
        return true;
    }

    LC_CMD_INTERACTIVETRANS(_jnidev);
};
//--------------------------------------------------------- 
/// 回调Handler接口OnWrite/OnRead进行通信的命令驱动
class JniCmdDriver : public CommonCmdDriver
{
protected:
    Ref<IBaseDevice> _activeDev;
    Ref<IInteractiveTrans> _activeTrans;
    Ref<ITimeoutBehavior> _activeTimeout;

    JniDevice _jnidev;
public:
    JniCmdDriver() : CommonCmdDriver()
    {
        _jnidev.ArraySize = DEV_BUFFER_SIZE;
        _activeTimeout = _jnidev;
        _activeDev = _jnidev;
        _activeTrans = _jnidev;

        _errGetter.Add(_jnidev);
        _logSetter.select(_jnidev);

        _RegisteCMD(JniCmdDriver, SetArraySize);
        _Registe("JniEnvCreate", _MakeCMD(JniCmdDriver, Open));
        _Registe("JniEnvDispose", _MakeCMD(JniCmdDriver, Close));

        _RegisteIBaseDeviceCMD(JniCmdDriver);
        _RegisteIInteractiveTransCMD(JniCmdDriver);
        _RegisteITimeoutCMD(JniCmdDriver);
        _RegisteCancelCMD(JniCmdDriver);

        _RegisteInterfaceCMD(JniCmdDriver, IBaseDevice);
        _RegisteInterfaceCMD(JniCmdDriver, IInteractiveTrans);
        _RegisteInterfaceCMD(JniCmdDriver, ITimeoutBehavior);
    }
    /* Interface */
    LC_CMD_INTERFACE_GETTER(IBaseDevice, _activeDev);
    LC_CMD_INTERFACE_GETTER(IInteractiveTrans, _activeTrans);
    LC_CMD_INTERFACE_GETTER(ITimeoutBehavior, _activeTimeout);
    /**
     * @brief JNI初始化
     * @date 2016-06-14 20:38
     * 
     * @param [in] JNIEnv : pointer JniEnv虚拟器地址
     * @param [in] jobject : pointer Java上层对象地址
     */
    LC_CMD_METHOD(Open)
    {
        string sEnv = arg["JNIEnv"].To<string>();
        string sObj = arg["jobject"].To<string>();

        JNIEnv* env = reinterpret_cast<JNIEnv*>(ArgConvert::FromString<pointer>(sEnv));
        jobject obj = reinterpret_cast<jobject>(ArgConvert::FromString<pointer>(sObj));

        return _jnidev.JniEnvCreate(env, obj);
    }
    LC_CMD_METHOD(IsOpen)
    {
        return _jnidev.IsOpen();
    }
    LC_CMD_METHOD(Close)
    {
        _jnidev.JniEnvDispose();
        return true;
    }
    /**
     * @brief 设置JNI调用时的缓冲区大小
     * @date 2016-06-14 20:38
     * 
     * @param [in] ArraySize : uint 缓冲区大小
     */
    LC_CMD_METHOD(SetArraySize)
    {
        string sArraySize;
        if(!arg.Get("ArraySize", sArraySize))
            return false;
        _jnidev.ArraySize = ArgConvert::FromString<uint>(sArraySize);
        return true;
    }

    LC_CMD_TIMEOUT(_jnidev);
    LC_CMD_CANCEL(_jnidev);
    LC_CMD_INTERACTIVETRANS(_jnidev);
};
//--------------------------------------------------------- 
/// 直接回调ITransceiveTrans接口进行通信的命令驱动
class JniIccInvokeCmdDriver : public CommonCmdDriver
{
protected:
    Ref<ITransceiveTrans> _activeTrans;

    size_t _jniArraySize;
    JniInvoker _jni;
    JavaITransceiveTransInvoker _jnidev;

    bool _IsOpen()
    {
        return _jni.IsValid() && _jnidev.IsValid();
    }
public:
    JniIccInvokeCmdDriver() : CommonCmdDriver()
    {
        _jniArraySize = DEV_BUFFER_SIZE;
        _activeTrans = _jnidev;

        _errGetter.Add(_jnidev);
        _logSetter.select(_jnidev);

        _RegisteCMD(JniIccInvokeCmdDriver, SetArraySize);
        _Registe("JniEnvCreate", _MakeCMD(JniIccInvokeCmdDriver, Open));
        _Registe("JniEnvDispose", _MakeCMD(JniIccInvokeCmdDriver, Close));

        _RegisteExceptCMD(JniIccInvokeCmdDriver);
        _RegisteIBaseDeviceCMD(JniIccInvokeCmdDriver);

        _RegisteInterfaceCMD(JniIccInvokeCmdDriver, ITransceiveTrans);
    }
    /* Interface */
    LC_CMD_INTERFACE_GETTER(ITransceiveTrans, _activeTrans);
    /**
     * @brief JNI初始化
     * @date 2016-06-14 20:38
     * 
     * @param [in] JNIEnv : pointer JniEnv虚拟器地址
     * @param [in] jobject : pointer Java上层对象地址
     * @param [in] ArraySize : size_t [default:Null] 缓冲区大小
     */
    LC_CMD_METHOD(Open)
    {
        string sEnv = arg["JNIEnv"].To<string>();
        string sObj = arg["jobject"].To<string>();

        JNIEnv* env = reinterpret_cast<JNIEnv*>(ArgConvert::FromString<pointer>(sEnv));
        jobject obj = reinterpret_cast<jobject>(ArgConvert::FromString<pointer>(sObj));

        SetArraySize(arg, rlt);

        if(_jni.Create(env, obj))
        {
            if(_jnidev.Create(_jni, _jniArraySize))
            {
                return true;
            }
            _logErr(DeviceError::DevInitErr, "JniDev Create失败");
        }
        else
        {
            _logErr(DeviceError::DevInitErr, "Jni Create失败");
        }
        return false;
    }
    LC_CMD_METHOD(IsOpen)
    {
        ASSERT_FuncErr(_IsOpen(), DeviceError::DevAlreadyCloseErr);
        return true;
    }
    LC_CMD_METHOD(Close)
    {
        _jnidev.Dispose();
        _jni.Dispose();
        return true;
    }
    /**
     * @brief 设置JNI调用时的缓冲区大小
     * @date 2016-06-14 20:38
     * 
     * @param [in] ArraySize : size_t 缓冲区大小
     */
    LC_CMD_METHOD(SetArraySize)
    {
        string sArraySize;
        if(!arg.Get("ArraySize", sArraySize))
            return false;
        _jniArraySize = ArgConvert::FromString<uint>(sArraySize);
        if(_IsOpen())
        {
            return _jnidev.Create(_jni, _jniArraySize);
        }
        return true;
    }
    LC_CMD_EXCEPT()
    {
        EXCEPT_CMD(SetArraySize);
        return true;
    }
};
//--------------------------------------------------------- 
} // nemespace driver
} // namespace application
} // namespace zhou_yb
//--------------------------------------------------------- 
#endif // _LIBZHOUYB_JNICMDDRIVER_H_
//========================================================= 